package org.folio.rest.impl.other.delayjob.partydelay;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import io.vertx.core.Vertx;
import io.vertx.core.logging.Logger;
import io.vertx.core.logging.LoggerFactory;
import org.folio.cql2pgjson.exception.FieldException;
import org.folio.rest.impl.other.PartyUtil;
import org.folio.rest.impl.other.take.TakeInterface;
import org.folio.rest.jaxrs.model.Auxiliary;
import org.folio.rest.jaxrs.model.Party;
import org.folio.rest.jaxrs.model.PartyGroup;
import org.folio.rest.persist.PostgresClient;
import org.folio.rest.persist.cql.CQLWrapper;

import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.atomic.AtomicReference;

/**
 * @author lee
 */
public class PartyEndHandler implements TakeInterface,Runnable {
    private static volatile DelayQueue<PartyDelay> queue = new DelayQueue<>();
    private final static Logger logger = LoggerFactory.getLogger("modparty");
    private static Vertx vertx = null;
    private static String tenant;
    @Override
    public void run() {
        while (true) {
            try {
                PartyDelay item = queue.take();
                if (item != null)
                {
                    updateParty(item);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public PartyEndHandler(Vertx vertx, String tenant) {
        this.vertx = vertx;
        this.tenant = tenant;

        searchParty(tenant, vertx);
    }

    public   void initData()  {

        searchParty(tenant, vertx);
    }
   public   void everyDay(){

   }
   private   void searchParty(String tenantId, Vertx vertx) {
       logger.info(" 扫描 "+tenantId+" 今天活动结束的记录。。。");
        Date date = new Date();
        String dayStart = DateUtil.formatDateTime(DateUtil.beginOfDay(date));
        String dayEnd = DateUtil.formatDateTime(DateUtil.endOfDay(date));
        String query = "(isDel = 0 and partyEndDate >= " + dayStart + " and partyEndDate <= " + dayEnd + " and state <> 1 and approval == 1  and isCalendar = 0 )";
        CQLWrapper cql = null;
        try {
            cql = PartyUtil.getCQL(query, -1, -1, "party");
        } catch (FieldException e) {
            // TODO Auto-generated catch block
            logger.info("搜索当天活动出现意外:{}",e);
            return;
        }
        PostgresClient.getInstance(vertx, tenantId).get("party", Party.class, new String[]{"*"}, cql,
                true, false, reply -> {
                    if (reply.succeeded()) {
                        List<Party> list = reply.result().getResults();
                        list.forEach(action -> {
                            setJob(action );
                        });
                    }
                });
    }

    @Override
    public void updateJob(Party partyGroup ) {
        Date date = new Date();
        if (DateUtil.isIn(DateUtil.parse(partyGroup.getPartyEndDate()),
                DateUtil.beginOfDay(date), DateUtil.endOfDay(date))) {
            AtomicReference<Boolean> flag = new AtomicReference<>(false);
            queue.forEach(a -> {
                if (a.getTenantId().equals(tenant ) && a.getPartyId().equals(partyGroup.getId())) {
                    if (!DateUtil.formatDateTime(new Date(a.getExpTime())).equals(partyGroup.getPartyEndDate())) {
                        flag.set(true);
                    }
                    return;
                }
            });
            if (flag.get()) {
                //del job and add job
                delJob(partyGroup  );
                setJob(partyGroup);
            }
        } else {
            AtomicReference<Boolean> flag = new AtomicReference<>(false);
            queue.forEach(a -> {
                if (a.getTenantId().equals(tenant ) && a.getPartyId().equals(partyGroup.getId())) {
                    flag.set(true);
                    return;
                }
            });
            if (flag.get()) {
                //del job
                delJob(partyGroup  );
            }
        }
    }
    @Override
    public   void delJob(final Party partyGroup ) {
        if (ObjectUtil.isEmpty(partyGroup)) {
            logger.info(" add job err , partyGroup is null ");
            return;
        }

        if (StrUtil.isNullOrUndefined(tenant )) {
            logger.info(" add job err , tenantId is null ");
            return;
        }
        //PartyDelay partyDelay = createPartyDelay(partyGroup, tenantId);
        Optional<PartyDelay> filterResult = queue.stream().filter(a -> a.getPartyId().equals(partyGroup.getId())).findAny();
        if (!filterResult.isPresent()){
            return;
        }else{
            queue.remove(filterResult.get());
        }

    }

    @Override
    public void timeTake() {
       initData();
        logger.info("定时扫描今天活动结束的记录。。。");
    }

    @Override
    public   void removeAndFreed(final Party partyGroup ) {
        if (ObjectUtil.isEmpty(partyGroup)) {
            logger.info(" add job err , partyGroup is null ");
            return;
        }

        if (StrUtil.isNullOrUndefined(tenant )) {
            logger.info(" add job err , tenantId is null ");
            return;
        }
        //PartyDelay partyDelay = createPartyDelay(partyGroup, tenantId);
        Optional<PartyDelay> filterResult = queue.stream().filter(a -> a.getPartyId().equals(partyGroup.getId())).findAny();
        if (!filterResult.isPresent()){
            return;
        }else{
            queue.remove(filterResult.get());
            updateParty(filterResult.get());
            cleanAuxiliary(filterResult.get());
        }

    }
    private static void updateParty(PartyDelay partyDelay){
        PostgresClient pg = PostgresClient.getInstance( vertx, partyDelay.getTenantId());
        pg.getById("party",partyDelay.getPartyId(),PartyGroup.class,reply->{
            if (reply.succeeded()){
                PartyGroup result = reply.result();
                result.setState(1);
                pg.update("party",result,partyDelay
                .getPartyId(),updateReply->{
                    if (updateReply.succeeded() && !"0".equals(String.valueOf(updateReply.result().getUpdated()))){
                        cleanAuxiliary(partyDelay);
                        logger.info("活动编号为：【"+partyDelay.getPartyId()+"】的活动已经结束");
                    }else{
                        logger.info("活动编号为：【"+partyDelay.getPartyId()+"】的活动已经结束，但活动状态state更新失败");
                    }
                });
            }else {
                logger.info("查找活动编号为【"+partyDelay.getPartyId()+"】，查找失败！");
            }
        });
    }


    private static void cleanAuxiliary(PartyDelay partyDelay) {
        PostgresClient pg = PostgresClient.getInstance( vertx, partyDelay.getTenantId());
        if (!StrUtil.isNullOrUndefined(partyDelay.getDeviceId())) {
            pg.getById("auxiliary", partyDelay.getDeviceId(), Auxiliary.class, replyHandler -> {
                if (replyHandler.succeeded()) {
                    Auxiliary result = replyHandler.result();
                    Integer amount = result.getAmount();
                    Integer remainderAmount = result.getRemainder();
                    Integer occupyAmount = Integer.parseInt(partyDelay.getDeviceCount());
                    Integer resultAmount = remainderAmount + occupyAmount;
                    if (amount >= resultAmount) {
                        result.setRemainder(resultAmount);
                        pg.update("auxiliary", result, result.getId(), reply -> {
                            if (reply.succeeded()) {
                                logger.info("ID为【" + partyDelay.getDeviceId() + "】名称为" + result.getName() + "的设备释放成功");
                            }
                        });

                    }
                } else {
                    logger.error("找不到ID为【" + partyDelay.getDeviceId() + "】的设备", replyHandler.cause());
                }
            });
        }
        if (!StrUtil.isNullOrUndefined(partyDelay.getAddressId())) {
            pg.getById("auxiliary", partyDelay.getAddressId(), Auxiliary.class, replyHandler -> {
                if (replyHandler.succeeded()) {
                    Auxiliary result = replyHandler.result();
                    Integer amount = result.getAmount();
                    Integer remainderAmount = result.getRemainder();
                    Integer occupyAmount = Integer.parseInt(partyDelay.getAddressCount());
                    Integer resultAmount = remainderAmount + occupyAmount;
                    if (amount >= resultAmount) {
                        result.setRemainder(resultAmount);
                        pg.update("auxiliary", result, result.getId(), reply -> {
                            if (reply.succeeded()) {
                                logger.info("ID为【" + partyDelay.getAddressId() + "】名称为【" + result.getName() + "】的场地释放成功");
                            }
                        });

                    }
                } else {
                    logger.error("找不到ID为【" + partyDelay.getDeviceId() + "】的场地", replyHandler.cause());
                }
            });
        }
    }

    private static PartyDelay createPartyDelay(Party partyGroup, String tenantId) {
        DateTime expTime = DateUtil.parse(partyGroup.getPartyEndDate());
        PartyDelay partyDelay = new PartyDelay();
        partyDelay.setAddressCount(partyGroup.getVenueCount().toString());
        partyDelay.setDeviceId(partyGroup.getFacId());
        partyDelay.setAddressId(partyGroup.getVenueId());
        partyDelay.setDeviceCount(partyGroup.getFacCount());
        partyDelay.setExpTime(expTime.getTime());
        partyDelay.setPartyId(partyGroup.getId());
        partyDelay.setTenantId(tenantId);
        return partyDelay;
    }

    @Override
    public void update() {
        searchParty(tenant, vertx);
        logger.info("定时扫描今天活动结束的记录。。。");
    }

    @Override
    public void setJob(Party partyGroup) {
        if (ObjectUtil.isEmpty(partyGroup)) {
            logger.info(" add job err , partyGroup is null ");
            return;
        }

        if (StrUtil.isNullOrUndefined(tenant )) {
            logger.info(" add job err , tenantId is null ");
            return;
        }
        if (StrUtil.isNullOrUndefined(partyGroup.getPartyEndDate())) {
            logger.info(" add job err , partyEndDate is null ");
            return;
        }
        Date date = new Date();
        if (DateUtil.isIn(DateUtil.parse(partyGroup.getPartyEndDate()),
                DateUtil.beginOfDay(date), DateUtil.endOfDay(date)) && "1".equals(partyGroup.getApproval().toString())) {
            PartyDelay partyDelay = createPartyDelay(partyGroup, tenant );
            queue.add(partyDelay);
            logger.info("add queue job success, party name is " + partyGroup.getPartyName());
        } else {
            logger.info(" add job err , partyEndDate is not today end ");
            return;
        }
    }
}
